/*
 *	$Id: emobj.cpp 121 2009-06-10 23:14:02Z wabsie $
 */

#include "emobj.h" // Hvis andre #include's i denne fil end denne, så slet dem


Field::Field(const emobj* EMobject, fieldPoint::felttype _type) :
	styrke(EMobject->styrke),
	off(EMobject->off),
	ret(EMobject->ret),
	v(EMobject->v),

	mu(EMobject->material->mu),
	epsilon(EMobject->material->epsilon),
	nul_potentiale(EMobject->material->nul_potentiale),

	type(_type)
{
	// Intet her
}


pointcharge::Efield::Efield(const emobj* EMobject) : 
	Field(EMobject, fieldPoint::vektor_felt)
{
	// Intet her
}
fieldPoint pointcharge::Efield::calc(coord<3> R)
{
	/* Jvf. Cheng Eq. (3-15) */

	fieldPoint tmp(this->type);

	R = R - off; // Tillad translation af punktladning

    skalar Rnorm = R.norm();
    skalar denom = Rnorm*Rnorm*Rnorm;

    tmp.vfelt = R / denom;
    tmp.vfelt = tmp.vfelt * (styrke / (4*pi*epsilon));

	return tmp;
}

pointcharge::Vfield::Vfield(const emobj* EMobject) : 
	Field(EMobject, fieldPoint::skalar_felt)
{
	// Intet her
}
fieldPoint pointcharge::Vfield::calc(coord<3> R)
{
	// Jvf. Cheng Eq. (3-47)
	fieldPoint tmp(this->type);
	vektor<3> R0 = nul_potentiale;

    R = R - off;	// Tillad translation af punktladning
	R0 = R0 - off;	// ...

	const skalar r0 = R0.norm();
	const skalar r = R.norm();

	tmp.sfelt = (styrke/(4*pi*epsilon)) * ((r0 - r)/(r0*r));

	return tmp;
}

linecharge::Efield::Efield(const emobj* EMobject) : 
	Field(EMobject, fieldPoint::vektor_felt)
{
	// Intet her
}
fieldPoint linecharge::Efield::calc(coord<3> R)
{
	fieldPoint tmp(this->type);

	R = R - off;	// Tillad translation af linieladningen

	tmp.vfelt.x = v.y*(R.x*v.y - R.y*v.x) - v.z*(R.z*v.x - R.x*v.z); // v &x (R &x v)
	tmp.vfelt.y = v.z*(R.y*v.z - R.z*v.y) - v.x*(R.x*v.y - R.y*v.x);
	tmp.vfelt.z = v.x*(R.z*v.x - R.x*v.z) - v.y*(R.y*v.z - R.z*v.y);

	const skalar d1 = R.x*v.y - R.y*v.x; // Norm(R &x v)^2
	const skalar d2 = R.x*v.z - R.z*v.x;
	const skalar d3 = R.y*v.z - R.z*v.y;
	const skalar denom = d1*d1 + d2*d2 + d3*d3;

	tmp.vfelt = tmp.vfelt / denom;
	tmp.vfelt = tmp.vfelt * (styrke / (2*pi*epsilon));

    return tmp;
}

linecharge::Vfield::Vfield(const emobj* EMobject) : 
	Field(EMobject, fieldPoint::skalar_felt)
{
	// Intet her
}
fieldPoint linecharge::Vfield::calc(coord<3> R)
{
	fieldPoint tmp(this->type);
	vektor<3> R0 = nul_potentiale;

	R = R - off;	// Tillad translation af linieladningen
	R0 = R0 - off;	// ...

	const skalar f1 = R.x*v.y - R.y*v.x;		// Norm(R &x v)^2
	const skalar f2 = R.x*v.z - R.z*v.x;
	const skalar f3 = R.y*v.z - R.z*v.y;
	const skalar fac = f1*f1 + f2*f2 + f3*f3;

	const skalar ref1 = R0.x*v.y - R0.y*v.x;	// Norm(R0 &x v)^2
	const skalar ref2 = R0.x*v.z - R0.z*v.x;
	const skalar ref3 = R0.y*v.z - R0.z*v.y;
	const skalar ref = ref1*ref1 + ref2*ref2 + ref3*ref3;

    tmp.sfelt = log(fac / ref);
    tmp.sfelt = tmp.sfelt * (-styrke/(4*pi*epsilon));
	return tmp;
}

linecurrent::Bfield::Bfield(const emobj* EMobject) : 
	Field(EMobject, fieldPoint::vektor_felt)
{
	// Intet her
}
fieldPoint linecurrent::Bfield::calc(coord<3> R)
{
	fieldPoint tmp(this->type);

	R = R - off;	// Tillad translation af linieladningen

	tmp.vfelt.x = R.z*v.y - R.y*v.z;	// v &x R
	tmp.vfelt.y = R.x*v.z - R.z*v.x;
	tmp.vfelt.z = R.y*v.x - R.x*v.y;

	const skalar d1 = R.x*v.y - R.y*v.x; // Norm(R &x v)^2
	const skalar d2 = R.x*v.z - R.z*v.x;
	const skalar d3 = R.y*v.z - R.z*v.y;
	const skalar denom = d1*d1 + d2*d2 + d3*d3;

	tmp.vfelt = tmp.vfelt / denom;
	tmp.vfelt = tmp.vfelt * ((styrke*mu)/(2*pi));

	return tmp;
}

linecurrent::Afield::Afield(const emobj* EMobject) : 
	Field(EMobject, fieldPoint::vektor_felt)
{
	// Intet her
}
fieldPoint linecurrent::Afield::calc(coord<3> R)
{
	fieldPoint tmp(this->type);
	vektor<3> R0 = nul_potentiale;

	R = R - off;	// Tillad translation af linieladningen
	R0 = R0 - off;	// ...

	const skalar f1 = R.x*v.y - R.y*v.x;		// Norm(R &x v)^2
	const skalar f2 = R.x*v.z - R.z*v.x;
	const skalar f3 = R.y*v.z - R.z*v.y;
	const skalar fac = f1*f1 + f2*f2 + f3*f3;

	const skalar ref1 = R0.x*v.y - R0.y*v.x;	// Norm(R0 &x v)^2
	const skalar ref2 = R0.x*v.z - R0.z*v.x;
	const skalar ref3 = R0.y*v.z - R0.z*v.y;
	const skalar ref = ref1*ref1 + ref2*ref2 + ref3*ref3;

	tmp.vfelt = v * log(fac / ref);
    tmp.vfelt = tmp.vfelt * (-styrke*mu/(4*pi));

	return tmp;
}


Medium::Medium() :
	epsilon(epsilon0), mu(mu0),			// Default til vakuum
	nul_potentiale(vektor<3>(1, 0, 0))
{
	// Intet her
}

void Medium::addObj(emobj::type objtype, skalar styrke, vektor<3> off, vektor<3> ret)
{
	emobj* em;

	switch (objtype) {
		case emobj::pcharge :  em = new pointcharge(this, styrke, off, ret); break;
		case emobj::lcharge :  em = new linecharge(this,  styrke, off, ret); break;
		case emobj::lcurrent : em = new linecurrent(this, styrke, off, ret); break;
		default:
			return;	// Ukendt objekt 
	}

	this->push_back(em); // Tilføj kun kendte objekter
}

void Medium::setMediumRelative(skalar epsilon_r, skalar mu_r)
{
	this->epsilon = epsilon_r * epsilon0;
	this->mu = mu_r * mu0;
}


const char*	emobj::strType[] = {"PCharge", "LCharge", "LCurrent"};

emobj::emobj(Medium *m, skalar _styrke, vektor<3> offset, vektor<3> v_orient) :
	material(m),
	styrke(_styrke),
    off(offset)
{
	this->setOrient(v_orient);
}

void emobj::setOrient(const vektor<3>& v_orient)
{
	this->ret = v_orient;	// Husk den ikke-normaliserede retning
	this->v = v_orient / v_orient.norm(); // Normalisér
}

vektor<3> emobj::getOrient() const
{
	return this->ret;		// Giv brugeren den ikke-normaliserede retning
}

string emobj::getInfo(const char* fmt)
{
	char buf[BUFSIZ] = "";
	snprintf(buf, sizeof(buf), "%s(%s,[%s],[%s])", strType[mintype],
								fmtScientific(styrke, fmt).c_str(),
								off.toString(fmt).c_str(),
								ret.toString(fmt).c_str());
    return (string)buf;
}

string pointcharge::getInfo(const char* fmt)
{
	/* En punktladning er speciel ift. de andre idet den ikke har nogen orientering.
	 * - Men ved at kunne benytte samme abstrakte klasse (emobj) for alle 3
	 * emobjekter, følger der automatisk en orientering med. Vi ignorerer derfor blot
	 * denne orientering for punktladningen. */
	char buf[BUFSIZ] = "";
	snprintf(buf, sizeof(buf), "%s(%s,[%s])", strType[mintype],
								fmtScientific(styrke, fmt).c_str(),
								off.toString(fmt).c_str());
    return (string)buf;
}

pointcharge::pointcharge(Medium *m, skalar _Q, vektor<3> offset, vektor<3> v_orient) :
	emobj(m, _Q, offset, v_orient)
{
	this->mintype = emobj::pcharge;

	this->felt[Field::primary] = new Efield(this);
	this->felt[Field::potential] = new Vfield(this);
}


linecharge::linecharge(Medium *m, skalar _rho_l, vektor<3> offset, vektor<3> v_orient) :
	emobj(m, _rho_l, offset, v_orient)
{
	this->mintype = emobj::lcharge;

	this->felt[Field::primary] = new Efield(this);
	this->felt[Field::potential] = new Vfield(this);
}


linecurrent::linecurrent(Medium *m, skalar _I, vektor<3> offset, vektor<3> v_orient) :
	 emobj(m, _I, offset, v_orient)
{
	this->mintype = emobj::lcurrent;

	this->felt[Field::primary] = new Bfield(this);
	this->felt[Field::potential] = new Afield(this);
}
